package pv.map;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

import com.google.android.gms.maps.model.LatLng;

public class LocationHelper {
	Context context;
	LocationManager locationManager;
	Location currentLocation;
	private static final int TEN_SECONDS = 10000;
	private static final int TEN_METERS = 10;
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	protected boolean isAsk = false;

	protected static LocationHelper instance = new LocationHelper();

	public static synchronized LocationHelper getInstance() {
		return instance;
	}

	public boolean isAsk() {
		return isAsk;
	}

	public void setAsk(boolean isAsk) {
		this.isAsk = isAsk;
	}

	protected LocationHelper() {

	}

	public String getAddressCurrentLocation() {
		return getAddress(getCurrentLocation());
	}

	public Location getCurrentLocation() {
		return currentLocation;
	}

	public LatLng getLatLngFromAddress(String strAddress) {
		ConvertLatLong conver = new ConvertLatLongURL();
		List<LatLng> result = conver.convert(strAddress, context);
		if (result != null)
			return result.get(0);
		return null;
	}

	public String getAddress(Location loc) {

		if (loc == null || context == null)
			return "";
		Geocoder geocoder = new Geocoder(context, Locale.getDefault());

		// Location loc = params[0];
		List<Address> addresses = null;
		try {
			addresses = geocoder.getFromLocation(loc.getLatitude(),
					loc.getLongitude(), 1);
		} catch (IOException e) {
			e.printStackTrace();
			// Update address field with the exception.
		}
		if (addresses != null && addresses.size() > 0) {
			Address address = addresses.get(0);
			// Format the first line of address (if available), city, and
			// country name.
			String addressText = String.format("%s, %s, %s", address
					.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0)
					: "", address.getLocality(), address.getCountryName());

			return addressText;
		}
		return "";

	}

	public void init(Context context) {
		this.context = context;
		if (context != null)
			locationManager = (LocationManager) context
					.getSystemService(Context.LOCATION_SERVICE);
	}

	public void startListener() {
		setup();

	}

	public void removeListener() {

		locationManager.removeUpdates(listener);
	}

	public boolean isGPSPrviderEnable() {
		return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
	}

	protected void setup() {
		if (!checkIsGPSOnFirtAndAsk())
			return;
		Location gpsLocation = null;
		Location networkLocation = null;
		locationManager.removeUpdates(listener);
		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		String provider = locationManager.getBestProvider(criteria, true);

		gpsLocation = requestUpdatesFromProvider(LocationManager.GPS_PROVIDER);
		networkLocation = requestUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);

		locationManager.requestLocationUpdates(provider, 1, 0, listener);

		currentLocation = locationManager.getLastKnownLocation(provider);

		if (gpsLocation != null && networkLocation != null) {
			currentLocation = getBetterLocation(gpsLocation, networkLocation);
		} else if (gpsLocation != null) {
			currentLocation = gpsLocation;

		} else if (networkLocation != null) {
			currentLocation = networkLocation;
		}

	}

	protected Location getBetterLocation(Location newLocation,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return newLocation;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = newLocation.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved.
		if (isSignificantlyNewer) {
			return newLocation;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return currentBestLocation;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (newLocation.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(newLocation.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return newLocation;
		} else if (isNewer && !isLessAccurate) {
			return newLocation;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return newLocation;
		}
		return currentBestLocation;
	}

	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	private Location requestUpdatesFromProvider(final String provider) {
		Location location = null;
		if (locationManager.isProviderEnabled(provider)) {

			locationManager.requestLocationUpdates(provider, TEN_SECONDS,
					TEN_METERS, listener);
			location = locationManager.getLastKnownLocation(provider);
		}
		return location;
	}

	private final LocationListener listener = new LocationListener() {

		@Override
		public void onLocationChanged(Location location) {

			currentLocation = location;
		}

		@Override
		public void onProviderDisabled(String provider) {
		}

		@Override
		public void onProviderEnabled(String provider) {
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};

	public LatLng convertLatLngLocation(Location location) {
		return new LatLng(location.getLatitude(), location.getLongitude());
	}

	public boolean checkIsGPSOnFirtAndAsk() {

		if (!isGPSPrviderEnable()) {
			if (isAsk) {
				if (context != null) {
					new AlertDialog.Builder(context)
							.setTitle("GPS")
							.setMessage("Please enable GPS to use application!")
							.setPositiveButton("GPS Setting",
									new DialogInterface.OnClickListener() {

										@Override
										public void onClick(
												DialogInterface dialog,
												int which) {
											// TODO Auto-generated method stub
											dialog.dismiss();
											Intent intent = new Intent(
													android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);

											context.startActivity(intent);

										}
									})

							.setNegativeButton(
									context.getString(android.R.string.cancel),
									new DialogInterface.OnClickListener() {

										@Override
										public void onClick(
												DialogInterface dialog,
												int which) {
											// TODO Auto-generated method stub
											dialog.dismiss();
										}
									}).show();
				}
			}

			return false;
		}
		return true;
	}

}
